package com.jacky.iot;

import com.google.common.cache.Cache;
import org.checkerframework.checker.units.qual.C;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.UdpConfig;

import java.io.File;
import java.util.concurrent.TimeUnit;

public class TSCoapClient {

    private final static String ACCESS_TOKEN = "C1_TEST_TOKEN";
    private final static String COAP_HOST = "coap://localhost:5683";

    private static final File CONFIG_FILE = new File("Californium3.properties");
    private static final String CONFIG_HEADER = "Californium CoAP Properties file for client";
    private static final int DEFAULT_MAX_RESOURCE_SIZE = 2 * 1024 * 1024; // 2 MB
    private static final int DEFAULT_BLOCK_SIZE = 512;

    static {
        CoapConfig.register();
        UdpConfig.register();
    }

    private static Configuration.DefinitionsProvider DEFAULTS = new Configuration.DefinitionsProvider() {

        @Override
        public void applyDefinitions(Configuration config) {
            config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, DEFAULT_MAX_RESOURCE_SIZE);
            config.set(CoapConfig.MAX_MESSAGE_SIZE, DEFAULT_BLOCK_SIZE);
            config.set(CoapConfig.PREFERRED_BLOCK_SIZE, DEFAULT_BLOCK_SIZE);
        }
    };


    public static void main(String[] args) throws InterruptedException {
        Configuration config = Configuration.createWithFile(CONFIG_FILE, CONFIG_HEADER, DEFAULTS);
        Configuration.setStandard(config);

        CoapClient coapClient = new CoapClient();
//        postTelemetry(coapClient);
//        sendAttribute(coapClient);
//        sendClaim(coapClient);
        observeRpc(coapClient);
        TimeUnit.SECONDS.sleep(15);
    }

    // 发送遥测数据
    private static void postTelemetry(CoapClient client) throws InterruptedException {
        String telemetryUri = "%s/api/v1/%s/telemetry".formatted(COAP_HOST, ACCESS_TOKEN);

        Request req = new Request(CoAP.Code.POST);
        String payload = "{\"temperature\":32,\"humidity\":61}";
        req.setPayload(payload);
        req.getOptions().setContentFormat(MediaTypeRegistry.APPLICATION_JSON);
        client.setURI(telemetryUri);

        client.advanced(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("[Telemetry] response:" + response.getCode() + "-" + response.getResponseText());
            }

            @Override
            public void onError() {
                System.out.println("[Telemetry] request failed:");
            }
        }, req);
    }

    private static void sendAttribute(CoapClient client) {
        String attrUri = "%s/api/v1/%s/attributes".formatted(COAP_HOST, ACCESS_TOKEN);

        Request req = new Request(CoAP.Code.POST);
        String payload = "{\"firmwareVersion\":\"v1.0.0\",\"batteryLevel\":72}";
        req.setPayload(payload);
        req.getOptions().setContentFormat(MediaTypeRegistry.APPLICATION_JSON);
        client.setURI(attrUri);

        client.advanced(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("[Attributes] response:" + response.getCode() + "-" + response.getResponseText());
            }

            @Override
            public void onError() {
                System.out.println("[Attributes] request failed:");
            }
        }, req);
    }

    // 设备声明
    private static void sendClaim(CoapClient client) {
        String claimUri = "%s/api/v1/%s/claim".formatted(COAP_HOST, ACCESS_TOKEN);

        Request req = new Request(CoAP.Code.POST);
        String payload = "{\"secretKey\":\"Quzisige154s\"}";
        req.setPayload(payload);
        req.getOptions().setContentFormat(MediaTypeRegistry.APPLICATION_JSON);
        client.setURI(claimUri);

        client.advanced(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("[Claim] response:" + response.getCode() + "-" + response.getResponseText());
            }

            @Override
            public void onError() {
                System.out.println("[Claim] request failed:");
            }
        }, req);
    }

    private static void observeRpc(CoapClient client) {
        String rpcUri = "%s/api/v1/%s/rpc".formatted(COAP_HOST, ACCESS_TOKEN);

        Request req = new Request(CoAP.Code.GET);
        req.setObserve();

        client.setURI(rpcUri);
        client.advanced(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                if (response.isSuccess()) {
                    System.out.println("[RPC Observe] received command:" + response.getResponseText());
                } else {
                    System.out.println("[RPC Observe] Non-success response:" + response.getResponseText());
                }
            }

            @Override
            public void onError() {
                System.out.println("[RPC Observe] Connection lost or error");
            }
        }, req);
    }
}